#ifndef STUDIO_H
#define STUDIO_H

#include "configurable.h"
#include "scene.h"

#include <sstream>
#include <iomanip>
#include "camera.h"
#include "common/image/image.h"
#include "hdr_rgbe.h"
#include "animation.h"
namespace gemren
{

	struct studio :public gemren::configurable
	{
	private:
		studio& operator=(const studio&);
	protected:
		animation_context anim_data;
		typedef std::string string;
		gemren::configurable* get_conf_target(const string& name)
		{
			if(name=="scene") return thescene;
			if(name=="camera" || name =="cam") return cam;
			return 0;
		}
		virtual gemren::err_t set_my_int(std::string& atom, const int value)
		{
			if(atom=="width") setdim(value, height);
			else if(atom =="height") setdim(width, value);
			return ERR_BAD_PROP;
			return ERR_OK;
		}
		
		virtual gemren::err_t set_my_float(std::string& atom, const float value)
		{
			if(atom =="exposition") 
			{
				exposition = value;
				return ERR_OK_NOSCRATCH;
			}
			else
				return ERR_BAD_PROP;
			
		}
		virtual err_t set_my_string(std::string& atom, const std::string& value)
		{
			if(atom == "resolution")
			{
				std::string cpy(value);
				size_t xpos = cpy.find_first_of('x');
				if(xpos != string::npos) cpy[xpos] = ' ';
				std::stringstream ss(cpy);
				int nw, nh;
				ss>>nw>>nh;
				if(ss.fail()) return ERR_BAD_VAL;
				setdim(nw, nh);
				return ERR_OK;
			}
			else if(atom == "animation")
			{
				str_to_val(value, anim_data);
				anim_data.set_camera(*cam);
				spp = 0;
				return ERR_OK;
			}
			return ERR_BAD_PROP;
		}
	public:
		virtual void announce_properties(const std::string& prefix, property_announcer announcer)
		{
			string sw,sh;
			val_to_str(width, sw);
			val_to_str(height, sh);
			announcer("resolution", ANNOUNCED_STRING, (sw+"x"+sh).c_str());
			announcer("exposition", ANNOUNCED_FLOAT, val_to_str(exposition).c_str());
			cam->announce_properties(prefix+(prefix==""?"":".") + "camera", announcer);
			thescene->announce_properties(prefix+(prefix==""?"":".") + "scene", announcer);
			
			//announcer("animation", ANNOUNCED_STRING, val_to_str(anim_data).c_str()); //not complete for everyday use
		}
		gemren::scene* thescene;
		gemren::camera* cam;
		float exposition;
		int spp;
		int width, height; //todo add to camera
		studio(gemren::scene* s)//, RTcamera_basic *c = NULL)
			: thescene(s),
			  cam(0),
			  img(0), imgl(0), width(0), height(0), exposition(0), spp(0)
		{
			
		}
		void clean()
		{
			if(img)
				embree::alignedFree(img);
			
			img = 0;
			imgl = 0;
			delete thescene;
			delete cam;
			thescene = 0;
			cam = 0;
		}
		embree::Col3f* img;
		int imgl;
		
		void getdim(int& w, int& h)
		{
			w = width; h = height;
		}
		void setdim(int w, int h)
		{
			width = w; height = h;
			if(imgl<w*h)
			{
				if(img)
				{
					embree::alignedFree(img);
				}
				img = (embree::Col3f*) embree::alignedMalloc( sizeof(embree::Col3f)*w*h);
				imgl = w*h;
			}
			spp = 0;
		}
		int save_image(const string& filename)
		{
			if(filename.substr(filename.find_last_of('.')) == ".hdr")
			{
				return store_hdr(filename.c_str(), img, width, height) ? 0 : 1;
			}
			return 0;
		}
		void prepare_shot()
		{//in the animations
			if(!anim_data) return;
			
			if(anim_data.spp <= spp)
			{ //frame is done
				std::stringstream ss;
				ss<<anim_data<<"_"<<std::setw( 6 ) << std::setfill( '0' )<<anim_data.frameno<<".hdr";
				save_image(ss.str());
				anim_data.set_camera(*cam);
				spp = 0;
			}
			
		}
	};
	

}


#endif